#include "cryptography.h"

#include <string>
using std::string;

using namespace std;

cryptography::cryptography(){}

cryptography::cryptography(string name)
{
    ////
    ////OJO
    ////AQUI DEBO CREAR LAS LLAVES DEL OBJETO
    ////

}

void cryptography::create_key(){
    InvertibleRSAFunction params;
    params.GenerateRandomWithKeySize( rng,  512);
    RSA::PrivateKey pri( params );

    RSA::PublicKey pub(pri);

    SavePublicKey("KG.pub",pub);
    SavePrivateKey("KG.pri",pri);

}

string cryptography::encryptMsg(const string &Data){
    string cipher;
    RSA::PublicKey pub;

    LoadPublicKey("KG.pub",pub);

    RSAES_OAEP_SHA_Encryptor e( pub);
    StringSource( Data, true,
        new PK_EncryptorFilter( rng, e,
            new StringSink( cipher )
        ) // PK_EncryptorFilter
     ); // StringSource
    return cipher;
}

string cryptography::decryptMsg(const string &Data){
    string recovered;
    RSA::PrivateKey pri;
    //pri.Load(StringSource(privateKey, true, new HexDecoder()).Ref());

    LoadPrivateKey("KG.pri",pri);

    RSAES_OAEP_SHA_Decryptor d( pri );

    StringSource( Data, true,
        new PK_DecryptorFilter( rng, d,
            new StringSink( recovered )
        ) // PK_DecryptorFilter
     ); // StringSource

    return recovered;
}

void cryptography::SavePrivateKey(const string &filename, const PrivateKey &key){
    ByteQueue queue;
    key.Save(queue);

    Save(filename, queue);
}

void cryptography::SavePublicKey(const string &filename, const PublicKey &key){
    ByteQueue queue;
    key.Save(queue);

    Save(filename, queue);
}

void cryptography::Save(const string &filename, const BufferedTransformation &bt){
    FileSink file(filename.c_str());

    bt.CopyTo(file);
    file.MessageEnd();
}

void cryptography::LoadPublicKey(const string &filename, PublicKey &key){
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html
    ByteQueue queue;

    Load(filename, queue);
    key.Load(queue);
}

void cryptography::LoadPrivateKey(const string &filename, PrivateKey &key){
    // http://www.cryptopp.com/docs/ref/class_byte_queue.html
    ByteQueue queue;

    Load(filename, queue);
    key.Load(queue);
}

void cryptography::Load(const string& filename, BufferedTransformation& bt)
{
        // http://www.cryptopp.com/docs/ref/class_file_source.html
        FileSource file(filename.c_str(), true /*pumpAll*/);

        file.TransferTo(bt);
        bt.MessageEnd();
}

string cryptography::getKey(){

    string g;
/*    FileSource file("key_generator.pubkey",true);

    ByteQueue queue;
    file.TransferTo(queue);
    queue.Get(s);*/
    //CryptoPP::HexEncoder encoder( new CryptoPP::StringSink(s),true /* Uppercase */, 2 /* Grouping */, ":" /* Separator */ );
    //g=(const char*)s;
    return g;
}

string cryptography::HashSingleData(const std::string &strData) {
    string output;
    SHA sha;

    SecByteBlock sbbDigest(sha.DigestSize());

    sha.CalculateDigest(sbbDigest.begin(), (byte const*) strData.data(), strData.size());
    HexEncoder(new StringSink(output)).Put(sbbDigest.begin(), sbbDigest.size());

    return output;
}

char cryptography::HashMultiData(const std::string &strDataPart1, const std::string &strDataPart2, const std::string &strDataPart3){
    SHA sha;
    char const* output;

    sha.Update((byte const*) strDataPart1.data(), strDataPart1.size());
    sha.Update((byte const*) strDataPart2.data(), strDataPart2.size());
    sha.Update((byte const*) strDataPart3.data(), strDataPart3.size());

    SecByteBlock sbbDigest(sha.DigestSize());

    sha.Final(sbbDigest.begin());
    HexEncoder(new FileSink(output)).Put(sbbDigest.begin(), sbbDigest.size());

    return *output;
}
